#include <jni.h>
#include <string>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>
#include "android/log.h"

static const char *TAG = "david";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)

extern "C" JNIEXPORT jstring JNICALL
Java_com_maniu_serialportnative_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
static speed_t getBaudrate(jint baudrate) {
    switch (baudrate) {
        case 0:

            return B0;
        case 50:
            return B50;
        case 75:
            return B75;
        case 110:
            return B110;
        case 134:
            return B134;
        case 150:
            return B150;
        case 200:
            return B200;
        case 300:
            return B300;
        case 600:
            return B600;
        case 1200:
            return B1200;
        case 1800:
            return B1800;
        case 2400:
            return B2400;
        case 4800:
            return B4800;
        case 9600:
            return B9600;
        case 19200:
            return B19200;
        case 38400:
            return B38400;
        case 57600:
            return B57600;
        case 115200:
            return B115200;
        case 230400:
            return B230400;
        case 460800:
            return B460800;
        case 500000:
            return B500000;
        case 576000:
            return B576000;
        case 921600:
            return B921600;
        case 1000000:
            return B1000000;
        case 1152000:
            return B1152000;
        case 1500000:
            return B1500000;
        case 2000000:
            return B2000000;
        case 2500000:
            return B2500000;
        case 3000000:
            return B3000000;
        case 3500000:
            return B3500000;
        case 4000000:
            return B4000000;
        default:
            return -1;

    }


}
//串口 开发板，root   手机app   基本没有root   只能  root
extern "C"
JNIEXPORT jobject JNICALL
Java_com_maniu_serialportnative_SerialPort_open(JNIEnv *env, jobject thiz, jstring path,
                                                jint baudrate, jint dataBits, jint parity,jint stopBits ) {

//    baudrate   文件   设值      串口 设值

    int fd;
    jboolean iscopy;
    const char *path_utf = env->GetStringUTFChars( path, &iscopy);
    fd = open(path_utf, O_RDWR );
    /*定义一个termios结构体  写入   4个 东西  */
//    c_cflag  停止位
//c_oflag  输出模式
    struct termios cfg;
// 写入参数
    if (tcgetattr(fd, &cfg)) {
        LOGE("tcgetattr() failed");
        close(fd);
        /* TODO: throw an exception */
        return NULL;
    }
//    标准  window  android  mac



//    ttytty子系统会将从串口收到的所有字节数据直接递交给应用层，而不进行额外处理，
    cfmakeraw(&cfg);
//    写入的参数配置 设值 速度     1  2     写  读    1      2
//15  =   9600
    cfsetispeed(&cfg,getBaudrate(baudrate));
//    波特位  写 1M 数据      间隔
    cfsetospeed(&cfg, getBaudrate(baudrate));
//c_cflag  数据

    cfg.c_cflag &= ~CSIZE;
    switch (dataBits) {
        case 5:
            cfg.c_cflag |= CS5;//使用5位数据位
            break;
        case 6:
            cfg.c_cflag  |= CS6; //使用6位数据位
            break;
        case 7:
            cfg.c_cflag  |= CS7; //使用7位数据位
            break;
        case 8:
            cfg.c_cflag  |= CS8;  //使用8位数据位
            break;

    }
//    奇偶校验 c_cflag

    switch (parity) {

        case 0:
            cfg.c_cflag &= ~PARENB;    //无奇偶校验

        case 1:
            cfg.c_cflag |= (PARODD | PARENB);   //奇校验
            break;
        case 2:
            cfg.c_iflag &= ~(IGNPAR | PARMRK); // 偶校验
            cfg.c_iflag |= INPCK;
            cfg.c_cflag |= PARENB;
            cfg.c_cflag &= ~PARODD;
            break;
        default:
            cfg.c_cflag &= ~PARENB; //无奇偶校验
            break;
    }
    switch (stopBits) {
        case 1:
            cfg.c_cflag &= ~CSTOPB;    //1位停止位
            break;
        case 2:
            cfg.c_cflag |= CSTOPB;    //2位停止位
            break;

        default:
            cfg.c_cflag &= ~CSTOPB;    //1位停止位
            break;
    }

    if (tcsetattr(fd, TCSANOW, &cfg)) {
        LOGE("tcsetattr() failed");
        close(fd);
        /* TODO: throw an exception */
        return NULL;

    }
//停止位  c_cflag
    jobject mFileDescriptor;
    jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor");
    jmethodID iFileDescriptor = env->GetMethodID(cFileDescriptor, "<init>", "()V");
    LOGE("tcgetattr() iFileDescriptor1");
    jfieldID descriptorID = env->GetFieldID(cFileDescriptor, "descriptor", "I");
    LOGE("tcgetattr() iFileDescriptor2");
    mFileDescriptor = env->NewObject(cFileDescriptor, iFileDescriptor);
    env->SetIntField(mFileDescriptor, descriptorID, (jint) fd);
    LOGE("tcgetattr() iFileDescriptor3");
    return mFileDescriptor;
}